#pragma once
#include "VTextureAtlas.h"

extern BOOL g_CubeTransformInit;
extern VMatrix g_CubeTransform[6];

void InitCubeTransform();

inline const VMatrix& GetCubeTransorm(int Face)
{
	if (!g_CubeTransformInit)
	{
		InitCubeTransform();
	}
	return g_CubeTransform[Face];
}


struct KLightRenderContext
{
	VMatrix LightTransform;
	VMatrix LightViewMatrix;
	VMatrix LightProjMatrix;
	VMatrix LightViewProjMatrix;
	VVector4 DepthRange;
};


struct KShadowRenderTexture : public VAllocator
{
	UINT Size;
	VRTexturePtr ShadowTexture;
};

struct KShadowRenderTarget: public VAllocator
{
	VRRenderTargetPtr RenderTarget;
	KShadowRenderTexture* ShadowTexture;
	BOOL HWShadow;
	UINT Size;
};

class KShadowRenderTargetCache
{
public:
	VPODArray<KShadowRenderTexture*> ShadowDepthOmniTextures;
	VPODArray<KShadowRenderTexture*> ShadowDepthProjTextures;
	VPODArray<KShadowRenderTarget*> ShadowDepthOmniRTs;
	VPODArray<KShadowRenderTarget*> ShadowDepthProjRTs;
	VRTexturePtr SharedColorRT;

	BOOL m_SupportHWShadow;

	KShadowRenderTargetCache()
	{
		m_SupportHWShadow = FALSE;
	}
	~KShadowRenderTargetCache(){}

	void RT_Init();
	void RT_Shutdown();

	inline void ReleaseRenderTexture_Omni(KShadowRenderTexture* RenderTexture)
	{
		ShadowDepthOmniTextures.PushBack(RenderTexture);
	}

	inline KShadowRenderTexture* GetRenderTexture_Omni(UINT Size)
	{
		for (UINT Index = 0; Index < ShadowDepthOmniTextures.Size(); ++Index)
		{
			KShadowRenderTexture*& Texture = ShadowDepthOmniTextures[Index];
			if (Texture->Size == Size)
			{
				ShadowDepthOmniTextures.EraseFast(Index);
				return Texture;
			}
		}
		return CreateRenderTexture_Omni(Size);
	}

	KShadowRenderTexture* CreateRenderTexture_Omni(UINT Size)
	{
		BOOL HW,PCF;
		VRTexturePtr DepthTexture = VEnv.RI->CreateProjectedShadowMapDepthRT(Size,HW,PCF);
		if (DepthTexture)
		{
			KShadowRenderTexture* RenderTexture = VNew KShadowRenderTexture;
			RenderTexture->ShadowTexture = DepthTexture;
			RenderTexture->Size = Size;
			return RenderTexture;
		}
		return NULL;
	}

	//////////////////////////////////////////////////////////////////////////
	//
	//////////////////////////////////////////////////////////////////////////

	inline void ReleaseRenderTarget_Omni(KShadowRenderTarget* RenderTarget)
	{
		ShadowDepthOmniRTs.PushBack(RenderTarget);
	}


	inline KShadowRenderTarget* GetRenderTarget_Omni(UINT Size)
	{
		for (UINT Index = 0; Index < ShadowDepthOmniRTs.Size(); ++Index)
		{
			KShadowRenderTarget*& RT = ShadowDepthOmniRTs[Index];
			if (RT->Size == Size)
			{
				ShadowDepthOmniRTs.EraseFast(Index);
				return RT;
			}
		}
		return CreateRenderTarget_Omni(Size);
	}

	KShadowRenderTarget* CreateRenderTarget_Omni(UINT Size)
	{
		VRTexture* ColorTargets[1] = {SharedColorRT};
		VRRenderTargetPtr RenderTarget = VEnv.RI->CreateRenderTarget(ColorTargets, 1, NULL);
		KShadowRenderTarget* SRT = VNew KShadowRenderTarget;
		SRT->RenderTarget = RenderTarget;
		return SRT;
	}

};

// hardware support
class KShadowRenderTargetCache_HW : public KShadowRenderTargetCache
{

};

class KShadowRenderTargetCache_SW : public KShadowRenderTargetCache
{

};

// shadow pool , for pack valid shadow frumstum in to one pooled texture.
class KShadowPool
{
public:
	inline KShadowPool(){}
	void Clear();
	void Init();
	void Shutdown();



private:
	VTextureAtlas* m_ShadowMapAtlas;
};



class KLightRenderer
{
public:
	static const int OmniShadowPackOffsetX[6];
	static const int OmniShadowPackOffsetY[6];
	enum{
		OMNI_SHADOW_PACK_NUM_ROW = 2,
		OMNI_SHADOW_PACK_NUM_COL = 3,
	};



};